use std::num::ParseIntError;

fn div(a: i32, b: i32) -> Result<f64, &'static str> {
    if b == 0 {
        Err("Cannot divide by zero")
    } else {
        Ok(a as f64 / b as f64)
    }
}

fn find(arr: &[i32]) -> Option<i32> {
    let e = arr.iter().find(|&x| x % 2 == 0)?;
    // ?操作符，在遇到Err或None程序会立即终止在当前，返回Error或None，并且下面打印不会执行
    println!("find");
    Some(*e)
}

// 报错传递或收集处理
fn parse(s: &str) -> Result<i32, ParseIntError> {
    // 报错传递
    let n = s.parse::<i32>()?;
    
    // 收集处理，下面map_err方法，只在返回Err(E)时调用，并且提供回调对Err进行处理返回，
    // 下面这里的处理加"?"，其实是为了与上面保持一致，不加"?"会直接得到处理后的Err类型，
    // 这样对Err管控又更进一步，非常有用
    let n = s.parse::<i32>().map_err(|err| Err(err))?

    Ok(n)
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 定义: rust中没有异常机制处理错误，而是主动采取机制来处错误

    // 可恢复错误
    // ?操作符
    // 用于简化Result或Option值匹配模式的样板代码，但在遇到Err或None程序会立即终止在当前；使用?操作符，外层函数务必实现Result或Some类型的返回
    let r = div(10, 2)?;
    println!("? : {}", r);

    // ?操作符 => Some
    let arr = [1, 3, 5, 7, 9];
    match find(&arr) {
        Some(e) => println!("find : {}", e),
        None => println!("not find"),
    }

    let arr = [1, 3, 6, 7, 9];
    match find(&arr) {
        Some(e) => println!("find : {}", e),
        None => println!("not find"),
    }

    // ?操作符 => Result
    match parse("123") {
        Ok(i) => println!("parse : {}", i),
        Err(e) => println!("parse error : {}", e),
    };

    match parse("abc") {
        Ok(i) => println!("parse : {}", i),
        Err(e) => println!("parse error : {}", e),
    };

    // 不可恢复错误
    // 程序bug，取值越界, 程序会奔溃，停止执行
    let v = vec![1, 2, 3];
    v[5];

    // panic!，主动触发恐慌，停止程序执行
    panic!("call panic!");

    Ok(())
}
